﻿using System;

namespace HelicalNumbers
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("==============================================================");
            Console.WriteLine("=                                                            =");
            Console.WriteLine("= Give me an integer greater than 1,                         =");
            Console.WriteLine("= I will show you a helical sequence from 1 to the number.   =");
            Console.WriteLine("=                                                            =");
            Console.WriteLine("==============================================================");

            int n;
            while (true)
            {
                Console.Write("\nPlease enter a number: ");
                var input = Console.ReadLine();
                if (int.TryParse(input, out n) && n > 1)
                {
                    // get result
                    int[,] helix = GenerateHelicalNumbers(n);

                    // print result
                    Console.WriteLine("\nHere is your helix (clockwise):");
                    Console.ForegroundColor = ConsoleColor.Green;

                    for (int i = 0; i < helix.GetLength(0); i++)
                    {
                        for (int j = 0; j < helix.GetLength(1); j++)
                        {
                            var num = helix[i, j];
                            var output = num == 0 ? String.Empty : num.ToString();
                            Console.Write(output.PadLeft(n.ToString().Length + 1, ' '));
                        }
                        Console.WriteLine();
                    }

                    Console.ForegroundColor = ConsoleColor.Gray;

                    // exit or continue ?
                    Console.WriteLine("\nPress [x] key to exit, others to continue.");
                    var consoleKey = Console.ReadKey(true);
                    if (consoleKey.Key == ConsoleKey.X) break;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("\nWHAT THE HELL ARE YOU DOING !!!");
                    Console.ForegroundColor = ConsoleColor.Gray;
                }
            }
        }

        /// <summary>
        /// Generate clockwise helical numbers
        /// </summary>
        /// <param name="n">The end of number</param>
        /// <returns>An array(2D) contains a helical numbers </returns>
        static int[,] GenerateHelicalNumbers(int n)
        {
            int[,] ret = null;

            // calculate the length of each dimension
            // in this case, row and column are the same value
            var rank = (int)Math.Ceiling(Math.Sqrt(n));

            // init 2D array by rank value
            ret = new int[rank, rank];

            // calculate the position of number 1 in 2D array.
            var index = rank % 2 == 0
                ? (rank / 2 - 1)
                : (rank - 1) / 2;

            // let's go
            var row = index;
            var col = index;

            for (int i = 1; i <= n; i++)
            {
                ret[row, col] = i;
                if (i == 1)
                {
                    // first, go right
                    col++;
                }
                // when down is zero and left has number then go down
                else if (row < rank - 1 && col > 0 && ret[row + 1, col] == 0 && ret[row, col - 1] > 0)
                {
                    row++;
                }
                // when down has number and right is zero then go right
                else if (row < rank - 1 && col < rank - 1 && ret[row + 1, col] > 0 && ret[row, col + 1] == 0)
                {
                    col++;
                }
                // when up has number and left is zero then go left
                else if (row > 0 && col > 0 && ret[row - 1, col] > 0 && ret[row, col - 1] == 0)
                {
                    col--;
                }
                // when up is zero and right has number then go up
                else if (row > 0 && col < rank - 1 && ret[row - 1, col] == 0 && ret[row, col + 1] > 0)
                {
                    row--;
                }
            }
            return ret;
        }
    }
}
